 /*******************************************************************************
  * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.update.internal.core;

 import java.io.BufferedWriter ;
 import java.io.File ;
 import java.io.FileOutputStream ;
 import java.io.IOException ;
 import java.io.OutputStream ;
 import java.io.OutputStreamWriter ;
 import java.io.UnsupportedEncodingException ;
 import java.io.Writer ;
 import java.text.DateFormat ;
 import java.text.SimpleDateFormat ;
 import java.util.Date ;

 import org.eclipse.core.runtime.FileLocator;
 import org.eclipse.update.configuration.IActivity;
 import org.eclipse.update.configuration.IInstallConfiguration;
 import org.eclipse.update.configurator.ConfiguratorUtils;
 import org.eclipse.update.configurator.IPlatformConfiguration;


 /**
  * A log writer that writes update manager log entries.
  */
 public class UpdateManagerLogWriter {
     private File logFile = null;
     private Writer log = null;

     private static final String CONFIGURATION = "!CONFIGURATION"; //$NON-NLS-1$
 private static final String ACTIVITY = "!ACTIVITY"; //$NON-NLS-1$

     private static final String SUCCESS = "success"; //$NON-NLS-1$
 private static final String FAILURE = "failure"; //$NON-NLS-1$

     private static final String FEATURE_INSTALL = "feature-install"; //$NON-NLS-1$
 private static final String FEATURE_REMOVE = "feature-remove"; //$NON-NLS-1$
 private static final String SITE_INSTALL = "site-install"; //$NON-NLS-1$
 private static final String SITE_REMOVE = "site-remove"; //$NON-NLS-1$
 private static final String UNCONFIGURE = "feature-disable"; //$NON-NLS-1$
 private static final String CONFIGURE = "feature-enable"; //$NON-NLS-1$
 private static final String REVERT = "revert"; //$NON-NLS-1$
 private static final String RECONCILIATION = "reconciliation"; //$NON-NLS-1$
 private static final String PRESERVED = "preserve-configuration"; //$NON-NLS-1$
 private static final String UNKNOWN = "unknown"; //$NON-NLS-1$

     private static final String LINE_SEPARATOR;

     static {
         String s = System.getProperty("line.separator"); //$NON-NLS-1$
 LINE_SEPARATOR = s == null ? "\n" : s; //$NON-NLS-1$
 }

     /*
      *
      */
     public UpdateManagerLogWriter(File file) {
         this.logFile = file;
         UpdateCore.warn("UPDATE MANAGER LOG Location: "+file.getAbsolutePath()); //$NON-NLS-1$

         // If the file does not exist, prime it with the sites in the exisiting config
 if (!file.exists())
             initLog();
     }
     
     /*
      * Initializes the log with the original configuration
      */
     private void initLog() {
         try {
             IPlatformConfiguration runtimeConfig = ConfiguratorUtils.getCurrentPlatformConfiguration();
             IPlatformConfiguration.ISiteEntry[] sites = runtimeConfig.getConfiguredSites();
             ConfigurationActivity[] activities = new ConfigurationActivity[sites.length];
             for (int i=0; i<sites.length; i++) {
                 activities[i] = new ConfigurationActivity(IActivity.ACTION_SITE_INSTALL);
                 activities[i].setLabel(FileLocator.toFileURL(sites[i].getURL()).toExternalForm());
                 activities[i].setDate(new Date ());
                 activities[i].setStatus(IActivity.STATUS_OK);
             }
             Date date = new Date (runtimeConfig.getChangeStamp());
             safeWriteConfiguration(date, activities);
         } catch (Exception e) {
             // silently ignore errors
 }
     }

     /*
      *
      */
     private void closeLogFile() throws IOException {
         try {
             if (log != null) {
                 log.flush();
                 log.close();
             }
         } finally {
             log = null;
         }
     }
     
     /*
      *
      */
     public void log(IInstallConfiguration installConfig) {
         safeWriteConfiguration(installConfig.getCreationDate(), installConfig.getActivities());
     }
     
     
     /*
      *
      */
     private void openLogFile() {
         try {
             log = new BufferedWriter (new OutputStreamWriter (new FileOutputStream (logFile.getAbsolutePath(), true), "UTF-8")); //$NON-NLS-1$
 } catch (IOException e) {
             // there was a problem opening the log file so log to the console
 log = logForStream(System.err);
         }
     }
     
     /*
      *
      */
     private String getFormattedDate(Date date) {
         try {
             DateFormat formatter = new SimpleDateFormat ("MMM dd, yyyy kk:mm:ss.SS"); //$NON-NLS-1$
 return formatter.format(date);
         } catch (Exception e) {
             // If there were problems writing out the date, ignore and
 // continue since that shouldn't stop us from losing the rest
 // of the information
 }
         return Long.toString(System.currentTimeMillis());
     }
     
     /*
      *
      */
     private Writer logForStream(OutputStream output) {
         try {
             return new BufferedWriter (new OutputStreamWriter (output, "UTF-8")); //$NON-NLS-1$
 } catch (UnsupportedEncodingException e) {
             return new BufferedWriter (new OutputStreamWriter (output));
         }
     }
     
     
     /*
      * Shuts down the update manager log.
      */
     public synchronized void shutdown() {
         try {
             if (logFile != null) {
                 closeLogFile();
                 logFile = null;
             } else {
                 if (log != null) {
                     Writer old = log;
                     log = null;
                     old.flush();
                     old.close();
                 }
             }
         } catch (IOException e) {
             //we've shutdown the log, so not much else we can do!
 e.printStackTrace();
         }
     }

     /*
      *
      */
     private synchronized void safeWriteConfiguration(Date date, IActivity[] activities) {
         // thread safety: (Concurrency003)
 if (logFile != null)
             openLogFile();
         if (log == null)
             log = logForStream(System.err);
         try {
             try {
                 write(date, activities);
             } finally {
                 if (logFile != null)
                     closeLogFile();
                 else
                     log.flush();
             }
         } catch (Exception e) {
             System.err.println("An exception occurred while writing to the update manager log:"); //$NON-NLS-1$
 e.printStackTrace(System.err);
             System.err.println("Logging to the console instead."); //$NON-NLS-1$
 //we failed to write, so dump log entry to console instead
 try {
                 log = logForStream(System.err);
                 write(date, activities);
                 log.flush();
             } catch (Exception e2) {
                 System.err.println("An exception occurred while logging to the console:"); //$NON-NLS-1$
 e2.printStackTrace(System.err);
             }
         } finally {
             log = null;
         }
     }
     

     /*
      * !CONFIGURATION <label>
      */
     private void write(Date date, IActivity[] activities) throws IOException {
         writeln();
         write(CONFIGURATION);
         writeSpace();
         write(String.valueOf(date.getTime()));
         writeSpace();
         write(date.toString());
         writeln();
         for (int i = 0; i < activities.length; i++) {
             write(activities[i]);
         }
     }

     /*
      * !ACTIVITY <date> <target> <action> <status>
      */
     private void write(IActivity activity) throws IOException {
         write(ACTIVITY);
         writeSpace();
         write(String.valueOf(activity.getDate().getTime()));
         writeSpace();
         write(getFormattedDate(activity.getDate()));
         writeSpace();
         write(activity.getLabel());
         writeSpace();
         write(getAction(activity.getAction()));
         writeSpace();
         write((activity.getStatus()==IActivity.STATUS_OK)?SUCCESS:FAILURE);
         writeln();
     }

     /*
      *
      */
     private String getAction(int i) {
         switch (i) {
             case IActivity.ACTION_FEATURE_INSTALL :
                 return FEATURE_INSTALL;
             case IActivity.ACTION_FEATURE_REMOVE :
                 return FEATURE_REMOVE;
             case IActivity.ACTION_SITE_INSTALL :
                 return SITE_INSTALL;
             case IActivity.ACTION_SITE_REMOVE :
                 return SITE_REMOVE;
             case IActivity.ACTION_UNCONFIGURE :
                 return UNCONFIGURE;
             case IActivity.ACTION_CONFIGURE :
                 return CONFIGURE;
             case IActivity.ACTION_REVERT :
                 return REVERT;
             case IActivity.ACTION_RECONCILIATION :
                 return RECONCILIATION;
             case IActivity.ACTION_ADD_PRESERVED :
                 return PRESERVED;
                             
             default :
                 return UNKNOWN+" ["+i+"]"; //$NON-NLS-1$ //$NON-NLS-2$
 }
     }


     /*
      *
      */
     private void writeln() throws IOException {
         write(LINE_SEPARATOR);
     }
     
     /*
      *
      */
     private void write(String message) throws IOException {
         if (message != null)
             log.write(message);
     }
     
     /*
      *
      */
     private void writeSpace() throws IOException {
         write(" "); //$NON-NLS-1$
 }
 }

